package cn.fintecher.pangolin.service.business.service;

import cn.fintecher.pangolin.common.enums.*;
import cn.fintecher.pangolin.common.exception.BadRequestException;
import cn.fintecher.pangolin.common.model.DepartmentModel;
import cn.fintecher.pangolin.common.model.UserModel;
import cn.fintecher.pangolin.common.utils.ZWDateUtil;
import cn.fintecher.pangolin.entity.elastic.BaseCase;
import cn.fintecher.pangolin.entity.elastic.HistoryCases;
import cn.fintecher.pangolin.entity.mysql.CaseInfo;
import cn.fintecher.pangolin.entity.mysql.QCaseInfo;
import cn.fintecher.pangolin.entity.mysql.QStatusConfig;
import cn.fintecher.pangolin.entity.mysql.StatusConfig;
import cn.fintecher.pangolin.service.business.model.CardInfoModel;
import cn.fintecher.pangolin.service.business.model.request.CollectingCasesRequest;
import cn.fintecher.pangolin.service.business.model.request.FindRetireCaseRequest;
import cn.fintecher.pangolin.service.business.model.request.ModifyCommentRequest;
import cn.fintecher.pangolin.service.business.model.request.UpdateStatusRequest;
import cn.fintecher.pangolin.service.business.model.response.*;
import cn.fintecher.pangolin.service.business.repository.elasticsearch.BaseCaseRespository;
import cn.fintecher.pangolin.service.business.repository.elasticsearch.HistoryCasesRespository;
import cn.fintecher.pangolin.service.business.repository.jparepository.AssistCaseRepository;
import cn.fintecher.pangolin.service.business.repository.jparepository.CaseInfoRepository;
import cn.fintecher.pangolin.service.business.repository.jparepository.StatusConfigRepository;
import com.querydsl.core.BooleanBuilder;
import org.apache.commons.collections4.IterableUtils;
import org.apache.commons.lang.StringUtils;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.modelmapper.ModelMapper;
import org.modelmapper.TypeToken;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.data.elasticsearch.core.query.SearchQuery;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.persistence.EntityManager;
import java.lang.reflect.Type;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @Auther: xiaqun
 * @Description:
 * @Date: 14:30 2019/9/3
 */

@Service("caseCollectorService")
@Transactional(rollbackFor = Exception.class)
public class CaseCollectorService {
    @Autowired
    private BaseService baseService;

    @Autowired
    private CaseInfoRepository caseInfoRepository;

    @Autowired
    private AssistCaseRepository assistCaseRepository;

    @Autowired
    private ModelMapper modelMapper;

    @Autowired
    private BaseCaseRespository baseCaseRespository;

    @Autowired
    private EntityManager em;

    @Autowired
    private HistoryCasesRespository historyCasesRespository;

    @Autowired
    private StatusConfigRepository statusConfigRepository;

    /**
     * 查询登录人相关的委托方
     */
    public Set<PrincipalResponse> findPrincipal(String token) {
        UserModel userModel = baseService.getUserByToken(token);
        DepartmentModel departmentModel = baseService.getDepartmentByToken(token);
        List<Object[]> list = new ArrayList<>();
        if (Objects.equals(userModel.getIsManage(), BaseSelect.YES)) { //是管理员
            List<Object[]> list1 = caseInfoRepository.findPrincipalByManager(departmentModel.getDepartCode());
            List<Object[]> list2 = assistCaseRepository.findPrincipalByManager(departmentModel.getDepartCode());
            list.addAll(list1);
            list.addAll(list2);
        } else { //不是管理员
            List<Object[]> list1 = caseInfoRepository.findPrincipalByCollector(userModel.getId());
            List<Object[]> list2 = assistCaseRepository.findPrincipalByCollector(userModel.getId());
            list.addAll(list1);
            list.addAll(list2);
        }
        if (!list.isEmpty()) {
            Set<PrincipalResponse> set = new HashSet<>();
            if (userModel.getIsCheck().equals(BaseSelect.YES)) {
                list.forEach(e -> {
                    if (userModel.getPrincipalIds().contains(e[0].toString())) {
                        PrincipalResponse response = new PrincipalResponse();
                        response.setId(e[0].toString());
                        response.setName(e[1].toString());
                        set.add(response);
                    }
                });
            } else {
                list.forEach(e -> {
                    PrincipalResponse response = new PrincipalResponse();
                    response.setId(e[0].toString());
                    response.setName(e[1].toString());
                    set.add(response);
                });
            }
            return set;
        } else {
            return new HashSet<>();
        }
    }

    /**
     * 在催案件查询
     */
    public Page<CollectingCasesResponse> findAllInCollectCase(CollectingCasesRequest request, Pageable pageable, String token) {
        UserModel userModel = baseService.getUserByToken(token);
        BooleanBuilder builder = request.generateQueryBuilder();
        builder.and(QCaseInfo.caseInfo.currentCollector.isNotNull());
        if (userModel.getIsCheck().equals(BaseSelect.YES)) {
            builder.and(QCaseInfo.caseInfo.principalId.in(userModel.getPrincipalIds()));
        }
        Sort sort = new Sort(Sort.Direction.ASC, "delegationDate")
                .and(new Sort(Sort.Direction.ASC, "followTime"))
                .and(new Sort(Sort.Direction.DESC, "overdueAmtTotal"));
        pageable = PageRequest.of(pageable.getPageNumber(), pageable.getPageSize(), sort);
        Page<CaseInfo> page = caseInfoRepository.findAll(builder, pageable);
        return page.map(e -> modelMapper.map(e, CollectingCasesResponse.class));
    }

    /**
     * 查询委托方案件
     */
    public Page<CollectingCasesResponse> findAllCaseByPrincipal(CollectingCasesRequest request, Pageable pageable, String token) {
        setJurisdiction(request, token);
        BooleanBuilder builder = request.generateQueryBuilder();
        Page<CaseInfo> page = caseInfoRepository.findAll(builder, pageable);
        return page.map(e -> modelMapper.map(e, CollectingCasesResponse.class));
    }

    /**
     * 退案案件查询
     */
    public Page<FindRetireCaseResponse> findAllRetireCase(FindRetireCaseRequest request, Pageable pageable) {
        BoolQueryBuilder builder = request.getBuilder();
        SearchQuery searchQuery = new NativeSearchQueryBuilder().withQuery(builder).withPageable(pageable).build();
        Page<BaseCase> page = baseCaseRespository.search(searchQuery);
        return page.map(e -> modelMapper.map(e, FindRetireCaseResponse.class));
    }

    /**
     * 查询委托方下全部批次案件
     */
    public List<FindBatchCaseResponse> findAllBatchCase(String batchNumber, String principalId, String token) {
        UserModel userModel = baseService.getUserByToken(token);
        DepartmentModel departmentModel = baseService.getDepartmentByToken(token);
        StringBuilder builder = new StringBuilder("SELECT a.batch_number,a.principal_name,count(a.id),sum(a.overdue_amt_total) from case_info a ");
        if (userModel.getIsManage().equals(BaseSelect.YES)) { //是管理员
            builder.append("left join user b on a.current_collector_id = b.id left join department c on b.depart_id = c.id where c.depart_code like (\'")
                    .append(departmentModel.getDepartCode()).append("%\')");
        } else { //不是管理员
            builder.append("where a.current_collector_id = \'").append(userModel.getId()).append("\'");
        }
        if (StringUtils.isNotBlank(batchNumber)) {
            builder.append(" and a.batch_number = \'").append(batchNumber).append("\'");
        }
        builder.append(" and a.case_data_status != \'").append("PAUSE").append("\'");
        builder.append(" and a.principal_id = \'").append(principalId).append("\'");
        builder.append(" GROUP BY a.batch_number,a.principal_name");
        String sql = builder.toString();
        List<Object[]> list = em.createNativeQuery(sql).getResultList();
        if (!list.isEmpty()) {
            List<FindBatchCaseResponse> responses = new ArrayList<>();
            list.forEach(e -> {
                FindBatchCaseResponse response = new FindBatchCaseResponse();
                response.setBatchNumber(e[0].toString());
                response.setPrincipalName(e[1].toString());
                response.setTotalNumber(Integer.parseInt(e[2].toString()));
                response.setTotalAmt(Double.parseDouble(e[3].toString()));
                responses.add(response);
            });
            return responses;
        } else {
            return new ArrayList<>();
        }
    }

    /**
     * 查询委托方下全部案件
     */
    public Page<FindCaseResponse> findAllCase(CollectingCasesRequest request, Pageable pageable, String token) {
        setJurisdiction(request, token);
        BooleanBuilder builder = request.generateQueryBuilder();
        Sort sort = new Sort(Sort.Direction.ASC, "delegationDate")
                .and(new Sort(Sort.Direction.ASC, "followTime"))
                .and(new Sort(Sort.Direction.DESC, "overdueAmtTotal"));
        pageable = PageRequest.of(pageable.getPageNumber(), pageable.getPageSize(), sort);
        Page<CaseInfo> page = caseInfoRepository.findAll(builder, pageable);
        return page.map(e -> modelMapper.map(e, FindCaseResponse.class));
    }

    /**
     * 设置查询权限
     */
    private void setJurisdiction(CollectingCasesRequest request, String token) {
        UserModel userModel = baseService.getUserByToken(token);
        DepartmentModel departmentModel = baseService.getDepartmentByToken(token);
        request.setIsManage(userModel.getIsManage());
        request.setCode(departmentModel.getDepartCode());
        request.setUserId(userModel.getId());
    }

    /**
     * 跟进ID获取案件
     */
    public CaseInfoModelResponse getCaseInfoById(String caseId) {
        CaseInfo caseInfo = caseInfoRepository.findById(caseId).orElseThrow(() -> new BadRequestException(null, "caseInfo", "case.is.null"));
        BaseCase baseCase = baseCaseRespository.findById(caseId).orElseThrow(() -> new BadRequestException(null, "baseCase", "personal.is.null"));
        CaseInfoModelResponse response = modelMapper.map(baseCase, CaseInfoModelResponse.class);
        response.setDepartName(Objects.nonNull(caseInfo.getCurrentCollector()) ? caseInfo.getCurrentCollector().getDepartment().getName() : null);
        response.setCaseId(caseId);
        return response;
    }

    /**
     * 获取客户账号卡号
     */
    public List<CardInfoModel> getCardInfoByIdCard(String certificateNo, String caseId, String token) {
        UserModel userModel = baseService.getUserByToken(token);
        BoolQueryBuilder builder = new BoolQueryBuilder();
        builder.must(QueryBuilders.matchPhraseQuery("certificateNo.keyword", certificateNo));
        builder.must(QueryBuilders.matchPhraseQuery("isClear.keyword", BaseSelect.NO.name()));
        if (userModel.getIsCheck().equals(BaseSelect.YES)) {
            builder.must(QueryBuilders.termsQuery("principalId.keyword", userModel.getPrincipalIds()));
        }
        Iterable<BaseCase> baseCaseIterable = baseCaseRespository.search(builder);
        List<BaseCase> baseCases = IterableUtils.toList(baseCaseIterable);
        List<BaseCase> list = new ArrayList<>();
        for (BaseCase baseCase : baseCases) {
            if (baseCase.getId().equals(caseId)) {
                list.add(baseCase);
                baseCases.remove(baseCase);
                break;
            }
        }
        list.addAll(baseCases);
        if (!list.isEmpty()) {
            Type listType = new TypeToken<List<CardInfoModel>>() {
            }.getType();
            return modelMapper.map(list, listType);
        } else {
            return new ArrayList<>();
        }
    }

    /**
     * 查询案件记事本内容
     */
    public String getComment(String caseId) {
        CaseInfo caseInfo = caseInfoRepository.findById(caseId).orElseThrow(() -> new BadRequestException(null, "caseInfo", "case.is.null"));
        return caseInfo.getComment();
    }

    /**
     * 修改记事本内容
     */
    public void modifyComment(ModifyCommentRequest request) {
        Optional<CaseInfo> optional = caseInfoRepository.findById(request.getCaseId());
        if (!optional.isPresent()) {
            throw new BadRequestException(null, "caseInfo", "case.is.done");
        }
        CaseInfo caseInfo = optional.get();
        checkCase(caseInfo, request.getCaseType());
        caseInfo.setComment(request.getComment());
        caseInfo.setCommentUpdateTime(ZWDateUtil.getNowDateTime());
        caseInfoRepository.save(caseInfo);
    }

    /**
     * 查询案件状态
     */
    public CaseStatusResponse getCaseStatus(String caseId) {
        CaseInfo caseInfo = caseInfoRepository.findById(caseId).orElseThrow(() -> new BadRequestException(null, "caseInfo", "case.is.null"));
        CaseStatusResponse response = new CaseStatusResponse();
        response.setCaseDataStatus(caseInfo.getCaseDataStatus()); //案件状态
        response.setIsAssist(caseInfo.getIsAssist()); //协助状态
        response.setPayStatus(caseInfo.getPayStatus()); //还款状态
        response.setContactStatus(processStatusString(caseInfo.getContactStatus())); //联系状态
        response.setCollectStatus(processStatusString(caseInfo.getCollectStatus())); //催收状态
        return response;
    }

    /**
     * 解析状态字符串
     */
    private List<String> processStatusString(String string) {
        if (StringUtils.isBlank(string)) {
            return new ArrayList<>();
        } else {
            String[] str = string.split(",");
            return Arrays.asList(str);
        }
    }

    /**
     * 更新案件状态
     */
    public void updateStatus(UpdateStatusRequest request) {
        Optional<CaseInfo> optional = caseInfoRepository.findById(request.getCaseId());
        if (!optional.isPresent()) {
            throw new BadRequestException(null, "caseInfo", "case.is.done");
        }
        CaseInfo caseInfo = optional.get();
        checkCase(caseInfo, request.getCaseType());
        if (request.getStatusType().equals(StatusType.CONTACT_STATUS)) { //联系状态
            caseInfo.setContactStatus(updateStatusString(caseInfo.getContactStatus(), Objects.equals(request.getIsAdd(), 1), request.getStatus()));
        } else { //催收状态
            caseInfo.setCollectStatus(updateStatusString(caseInfo.getCollectStatus(), Objects.equals(request.getIsAdd(), 1), request.getStatus()));
        }
        //判断是否重点
        boolean b = false;
        String contactStr = caseInfo.getContactStatus();
        if (StringUtils.isNotBlank(contactStr)) {
            b = checkIsImportant(contactStr, StatusType.CONTACT_STATUS, caseInfo);
        }
        if (!b) {
            String collectStr = caseInfo.getCollectStatus();
            if (StringUtils.isNotBlank(collectStr)) {
                b = checkIsImportant(collectStr, StatusType.COLLECT_STATUS, caseInfo);
            }
        }
        if (b) {
            caseInfo.setIsImportant(BaseSelect.YES);
        } else {
            caseInfo.setIsImportant(BaseSelect.NO);
        }
        caseInfoRepository.save(caseInfo);
    }

    /**
     * 判断是否重点
     */
    private boolean checkIsImportant(String str, StatusType type, CaseInfo caseInfo) {
        boolean b = false;
        QStatusConfig qStatusConfig = QStatusConfig.statusConfig;
        String[] contact = str.split(",");
        for (String s : contact) {
            Optional<StatusConfig> statusConfigOptional = statusConfigRepository.findOne(qStatusConfig.principalId.eq(caseInfo.getPrincipalId())
                    .and(qStatusConfig.name.eq(s)).and(qStatusConfig.type.eq(type)));
            if (statusConfigOptional.isPresent()) {
                StatusConfig statusConfig = statusConfigOptional.get();
                if (statusConfig.getIsImportant().equals(BaseSelect.YES)) {
                    b = true;
                    break;
                }
            }
        }
        return b;
    }

    /**
     * 处理状态字符串
     */
    private String updateStatusString(String string, boolean b, String status) {
        if (b) { //新增
            if (StringUtils.isBlank(string)) { //原字符串为空
                return status;
            } else { //原字符串不为空
                if (string.contains(status)) { //原字符串包含
                    return string;
                } else { //原字符串不包含
                    return string + "," + status;
                }
            }
        } else { //减少
            if (StringUtils.isBlank(string)) { //原字符串为空
                return string;
            } else { //原字符串不为空
                if (string.contains(status)) { //原字符串包含
                    List<String> statusList = new ArrayList<>(Arrays.asList(string.split(",")));
                    List<String> collect = statusList.stream().filter(x -> x.equals(status)).collect(Collectors.toList());
                    if (!collect.isEmpty()) {
                        statusList.removeAll(collect);
                    }
                    return statusList.stream().collect(Collectors.joining(","));
                } else { //原字符串不包含
                    return string;
                }
            }
        }
    }

    /**
     * 查询委托方下批次号
     */
    public List<FindBatchCaseResponse> getBatchNumber(String principalId, String type) {
        BoolQueryBuilder builder = new BoolQueryBuilder();
        builder.must(QueryBuilders.matchPhraseQuery("principalId.keyword", principalId));
        List<FindBatchCaseResponse> list = new ArrayList<>();
        switch (type) {
            case "WAIT_DISTRIBUTE":
            case "DEPARTMENT":
            case "COLLECTING":
            case "PUBLIC":
            case "STOPPING":
                Iterable<BaseCase> iterable = baseCaseRespository.search(builder);
                List<BaseCase> baseCases = IterableUtils.toList(iterable);
                Map<String, List<BaseCase>> map = baseCases.stream().collect(Collectors.groupingBy(BaseCase::getBatchNumber));
                for (Map.Entry<String, List<BaseCase>> entry : map.entrySet()) {
                    FindBatchCaseResponse response = new FindBatchCaseResponse();
                    response.setBatchNumber(entry.getKey());
                    list.add(response);
                }
                break;
            case "RETURN":
            case "DELETE":
                Iterable<HistoryCases> iterable1 = historyCasesRespository.search(builder);
                List<HistoryCases> historyCases = IterableUtils.toList(iterable1);
                Map<String, List<HistoryCases>> map1 = historyCases.stream().collect(Collectors.groupingBy(HistoryCases::getBatchNumber));
                for (Map.Entry<String, List<HistoryCases>> entry : map1.entrySet()) {
                    FindBatchCaseResponse response = new FindBatchCaseResponse();
                    response.setBatchNumber(entry.getKey());
                    list.add(response);
                }
                break;
        }
        return list;
    }

    /**
     * 判断催收类型是否改变
     */
    private void checkCase(CaseInfo caseInfo, CaseType caseType) {
        if (!caseType.equals(caseInfo.getCaseType())) {
            throw new BadRequestException(null, "caseInfo", "case.type.is.change");
        }
        if (caseInfo.getCaseDataStatus().equals(CaseDataStatus.PAUSE)) {
            throw new BadRequestException(null, "caseInfo", "case.is.stop");
        }
        if (caseInfo.getCaseDataStatus().equals(CaseDataStatus.SETTLT) || caseInfo.getCaseDataStatus().equals(CaseDataStatus.REDUCE)) {
            throw new BadRequestException(null, "caseInfo", "case.is.clear");
        }
        if (caseInfo.getPublicCaseFlag().equals(PublicCaseFlag.PUBLIC_CASE)) {
            throw new BadRequestException(null, "caseInfo", "case.is.public");
        }
    }
}
